using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using System.IO;
using System.Text.Json;
using System.Collections.Generic;
using System.Windows;
using Tryit.Views;
using Microsoft.Win32;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Controls;
using OfficeOpenXml;
using System.Drawing;

namespace Tryit.ViewModels
{
    public class ScheduleViewModel : BindableBase
    {
        private DateTime _startDate = DateTime.Today;
        public DateTime StartDate
        {
            get => _startDate;
            set => SetProperty(ref _startDate, value);
        }

        private DateTime _endDate = DateTime.Today.AddDays(7);
        public DateTime EndDate
        {
            get => _endDate;
            set => SetProperty(ref _endDate, value);
        }

        private ObservableCollection<PersonItem> _availablePersons;
        public ObservableCollection<PersonItem> AvailablePersons
        {
            get => _availablePersons;
            set => SetProperty(ref _availablePersons, value);
        }

        private ObservableCollection<PersonItem> _selectedPersons;
        public ObservableCollection<PersonItem> SelectedPersons
        {
            get => _selectedPersons;
            set => SetProperty(ref _selectedPersons, value);
        }

        private ObservableCollection<ScheduleResult> _scheduleResults;
        public ObservableCollection<ScheduleResult> ScheduleResults
        {
            get => _scheduleResults;
            set => SetProperty(ref _scheduleResults, value);
        }

        private ObservableCollection<PersonStatistics> _personStatistics;
        public ObservableCollection<PersonStatistics> PersonStatistics
        {
            get => _personStatistics;
            set => SetProperty(ref _personStatistics, value);
        }

        private ObservableCollection<CalendarDay> _calendarDays;
        public ObservableCollection<CalendarDay> CalendarDays
        {
            get => _calendarDays;
            set => SetProperty(ref _calendarDays, value);
        }

        private PersonItem _selectedFilterPerson;
        public PersonItem SelectedFilterPerson
        {
            get => _selectedFilterPerson;
            set
            {
                if (SetProperty(ref _selectedFilterPerson, value))
                {
                    UpdateFilteredCalendarView();
                }
            }
        }

        private bool _showRestDays = true;
        public bool ShowRestDays
        {
            get => _showRestDays;
            set
            {
                if (SetProperty(ref _showRestDays, value))
                {
                    UpdateFilteredCalendarView();
                }
            }
        }

        public ICommand GenerateScheduleCommand { get; }
        public ICommand AddSelectedCommand { get; }
        public ICommand RemoveSelectedCommand { get; }
        public ICommand ShowStatisticsCommand { get; }
        public ICommand ExportToExcelCommand { get; }
        public ICommand ExportToImageCommand { get; }
        public ICommand UpdateScheduleCommand { get; }
        public ICommand ClearFilterCommand { get; }

        public ScheduleViewModel()
        {
            AvailablePersons = new ObservableCollection<PersonItem>();
            SelectedPersons = new ObservableCollection<PersonItem>();
            ScheduleResults = new ObservableCollection<ScheduleResult>();
            PersonStatistics = new ObservableCollection<PersonStatistics>();
            CalendarDays = new ObservableCollection<CalendarDay>();

            // 初始化命令
            GenerateScheduleCommand = new DelegateCommand(GenerateSchedule);
            AddSelectedCommand = new DelegateCommand(AddSelected);
            RemoveSelectedCommand = new DelegateCommand(RemoveSelected);
            ShowStatisticsCommand = new DelegateCommand(ShowStatistics);
            ExportToExcelCommand = new DelegateCommand(ExportToExcel);
            ExportToImageCommand = new DelegateCommand(ExportToImage);
            UpdateScheduleCommand = new DelegateCommand<CalendarDay>(UpdateSchedule);
            ClearFilterCommand = new DelegateCommand(ClearFilter);

            // 加载人员数据
            LoadPersonListFromFile();
        }

        private void ShowStatistics()
        {
            var statisticsWindow = new StatisticsView();
            var statisticsViewModel = statisticsWindow.DataContext as StatisticsViewModel;
            if (statisticsViewModel != null)
            {
                statisticsViewModel.UpdateStatistics(PersonStatistics);
            }
            statisticsWindow.ShowDialog();
        }

        private void LoadPersonListFromFile()
        {
            try
            {
                var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config");
                var filePath = Path.Combine(configPath, "persons.json");

                if (File.Exists(filePath))
                {
                    var json = File.ReadAllText(filePath);
                    var savedList = JsonSerializer.Deserialize<List<string>>(json);

                    if (savedList != null)
                    {
                        Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            AvailablePersons.Clear();
                            foreach (var person in savedList)
                            {
                                if (!AvailablePersons.Any(p => p.Name == person))
                                {
                                    AvailablePersons.Add(new PersonItem { Name = person });
                                }
                            }
                            RaisePropertyChanged(nameof(AvailablePersons));
                        }));
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载人员列表失败：{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void AddSelected()
        {
            var selectedItems = AvailablePersons.Where(p => p.IsSelected).ToList();
            foreach (var item in selectedItems)
            {
                if (!SelectedPersons.Any(p => p.Name == item.Name))
                {
                    SelectedPersons.Add(new PersonItem { Name = item.Name, IsSelected = false });
                }
            }
            foreach (var item in selectedItems)
            {
                AvailablePersons.Remove(item);
            }
            RaisePropertyChanged(nameof(AvailablePersons));
            RaisePropertyChanged(nameof(SelectedPersons));
        }

        private void RemoveSelected()
        {
            var selectedItems = SelectedPersons.Where(p => p.IsSelected).ToList();
            foreach (var item in selectedItems)
            {
                if (!AvailablePersons.Any(p => p.Name == item.Name))
                {
                    AvailablePersons.Add(new PersonItem { Name = item.Name, IsSelected = false });
                }
            }
            foreach (var item in selectedItems)
            {
                SelectedPersons.Remove(item);
            }
            RaisePropertyChanged(nameof(AvailablePersons));
            RaisePropertyChanged(nameof(SelectedPersons));
        }

        private class PersonSchedule
        {
            public string Name { get; set; }
            public DateTime LastWorkTime { get; set; }
            public int ConsecutiveWorkDays { get; set; }
            public int TotalShifts { get; set; }
            public int DaysSinceLastShift { get; set; }
            public int DayShifts { get; set; }
            public int NightShifts { get; set; }
            public int ConsecutiveNightShifts { get; set; }
            public int WeeklyNightShifts { get; set; }
            public DateTime WeekStart { get; set; }
        }

        private void UpdateFilteredCalendarView()
        {
            if (SelectedFilterPerson == null)
            {
                UpdateCalendarView();
                return;
            }

            CalendarDays.Clear();
            
            // 计算需要显示的天数（包括前后的空白日期）
            var startDate = StartDate.Date.AddDays(-(int)StartDate.DayOfWeek + 1); // 从周一开始
            var endDate = EndDate.Date.AddDays(7 - (int)EndDate.DayOfWeek); // 到周日结束

            for (var date = startDate; date <= endDate; date = date.AddDays(1))
            {
                // 检查日期是否在排班范围内
                bool isInScheduleRange = date >= StartDate && date <= EndDate;

                if (!isInScheduleRange)
                {
                    // 不在排班范围内的日期显示为空白
                    CalendarDays.Add(new CalendarDay
                    {
                        Date = date,
                        DayShift = null,
                        NightShift = null,
                        HasDayShift = false,
                        HasNightShift = false,
                        IsRestDay = false
                    });
                    continue;
                }

                var dayShifts = ScheduleResults.Where(r => r.Date.Date == date.Date && r.ShiftType == "白班" && r.PersonName == SelectedFilterPerson.Name).ToList();
                var nightShifts = ScheduleResults.Where(r => r.Date.Date == date.Date && r.ShiftType == "夜班" && r.PersonName == SelectedFilterPerson.Name).ToList();

                var hasAnyShift = dayShifts.Any() || nightShifts.Any();
                
                // 如果这一天没有排班且不显示休息日，则跳过
                if (!hasAnyShift && !ShowRestDays)
                {
                    continue;
                }

                CalendarDays.Add(new CalendarDay
                {
                    Date = date,
                    DayShift = dayShifts.Any() ? $"白班: {string.Join(", ", dayShifts.Select(s => s.PersonName))}" : null,
                    NightShift = nightShifts.Any() ? $"夜班: {string.Join(", ", nightShifts.Select(s => s.PersonName))}" : null,
                    HasDayShift = dayShifts.Any(),
                    HasNightShift = nightShifts.Any(),
                    IsRestDay = !hasAnyShift && ShowRestDays
                });
            }

            RaisePropertyChanged(nameof(CalendarDays));
        }

        private void UpdateCalendarView()
        {
            if (SelectedFilterPerson != null)
            {
                UpdateFilteredCalendarView();
                return;
            }

            CalendarDays.Clear();
            
            // 计算需要显示的天数（包括前后的空白日期）
            var startDate = StartDate.Date.AddDays(-(int)StartDate.DayOfWeek + 1); // 从周一开始
            var endDate = EndDate.Date.AddDays(7 - (int)EndDate.DayOfWeek); // 到周日结束

            for (var date = startDate; date <= endDate; date = date.AddDays(1))
            {
                var dayShifts = ScheduleResults.Where(r => r.Date.Date == date.Date && r.ShiftType == "白班").ToList();
                var nightShifts = ScheduleResults.Where(r => r.Date.Date == date.Date && r.ShiftType == "夜班").ToList();

                CalendarDays.Add(new CalendarDay
                {
                    Date = date,
                    DayShift = dayShifts.Any() ? $"白班: {string.Join(", ", dayShifts.Select(s => s.PersonName))}" : null,
                    NightShift = nightShifts.Any() ? $"夜班: {string.Join(", ", nightShifts.Select(s => s.PersonName))}" : null,
                    HasDayShift = dayShifts.Any(),
                    HasNightShift = nightShifts.Any(),
                    IsRestDay = false
                });
            }

            RaisePropertyChanged(nameof(CalendarDays));
        }

        private void GenerateSchedule()
        {
            if (SelectedPersons.Count == 0)
            {
                MessageBox.Show("请先选择人员！", "提示");
                return;
            }

            if (SelectedPersons.Count < 4)
            {
                MessageBox.Show("至少需要4名人员才能进行排班！", "提示");
                return;
            }

            if (EndDate < StartDate)
            {
                MessageBox.Show("结束日期不能早于开始日期！", "提示");
                return;
            }

            ScheduleResults.Clear();
            var random = new Random();
            var persons = SelectedPersons.Select(p => p.Name).ToList();

            // 记录每个人的排班情况
            var personSchedules = persons.ToDictionary(
                p => p,
                p => new PersonSchedule 
                { 
                    Name = p,
                    LastWorkTime = DateTime.MinValue,
                    ConsecutiveWorkDays = 0,
                    TotalShifts = 0,
                    DaysSinceLastShift = int.MaxValue,
                    DayShifts = 0,
                    NightShifts = 0,
                    ConsecutiveNightShifts = 0,
                    WeeklyNightShifts = 0,
                    WeekStart = StartDate.Date.AddDays(-(int)StartDate.DayOfWeek)
                }
            );

            // 白班时间：8:00-20:00，夜班时间：20:00-8:00
            var dayShiftStart = new TimeSpan(8, 0, 0);
            var nightShiftStart = new TimeSpan(20, 0, 0);
            
            // 计算需要排班的天数
            var days = (EndDate - StartDate).Days + 1;
            
            for (int day = 0; day < days; day++)
            {
                var currentDate = StartDate.AddDays(day);
                var currentDateTime = currentDate.Date;

                // 检查是否需要重置周统计
                foreach (var schedule in personSchedules.Values)
                {
                    if (currentDate.Date >= schedule.WeekStart.AddDays(7))
                    {
                        schedule.WeekStart = currentDate.Date.AddDays(-(int)currentDate.DayOfWeek);
                        schedule.WeeklyNightShifts = 0;
                    }
                }

                // 更新每个人的未排班天数
                foreach (var schedule in personSchedules.Values)
                {
                    if (schedule.LastWorkTime.Date < currentDate.Date)
                    {
                        schedule.DaysSinceLastShift++;
                    }
                }

                // 白班
                var dayShiftDateTime = currentDateTime.Add(dayShiftStart);
                var selectedPerson = SelectPersonForShift(personSchedules, dayShiftDateTime, 12, random, true);
                
                if (selectedPerson == null)
                {
                    MessageBox.Show($"第{day + 1}天白班没有合适的人员可以安排！", "警告");
                    continue;
                }

                UpdatePersonSchedule(personSchedules[selectedPerson], dayShiftDateTime, true);

                ScheduleResults.Add(new ScheduleResult
                {
                    ShiftNumber = day * 2 + 1,
                    Date = currentDate,
                    ShiftType = "白班",
                    PersonName = selectedPerson,
                    WorkTime = "08:00-20:00"
                });

                // 夜班
                var nightShiftDateTime = currentDateTime.Add(nightShiftStart);
                selectedPerson = SelectPersonForShift(personSchedules, nightShiftDateTime, 12, random, false);
                
                if (selectedPerson == null)
                {
                    MessageBox.Show($"第{day + 1}天夜班没有合适的人员可以安排！", "警告");
                    continue;
                }

                UpdatePersonSchedule(personSchedules[selectedPerson], nightShiftDateTime, false);

                ScheduleResults.Add(new ScheduleResult
                {
                    ShiftNumber = day * 2 + 2,
                    Date = currentDate,
                    ShiftType = "夜班",
                    PersonName = selectedPerson,
                    WorkTime = "20:00-08:00"
                });
            }

            // 更新统计信息
            UpdatePersonStatistics(personSchedules);

            // 检查是否有人从未被排班
            var unassignedPersons = personSchedules.Where(p => p.Value.TotalShifts == 0).Select(p => p.Key).ToList();
            if (unassignedPersons.Any())
            {
                MessageBox.Show($"以下人员未被安排任何班次：\n{string.Join("\n", unassignedPersons)}", "警告");
            }

            RaisePropertyChanged(nameof(ScheduleResults));

            // 在生成排班后更新日历视图
            UpdateCalendarView();
        }

        private void UpdatePersonStatistics(Dictionary<string, PersonSchedule> personSchedules)
        {
            PersonStatistics.Clear();
            foreach (var schedule in personSchedules.Values)
            {
                PersonStatistics.Add(new PersonStatistics
                {
                    Name = schedule.Name,
                    TotalShifts = schedule.TotalShifts,
                    DayShifts = schedule.DayShifts,
                    NightShifts = schedule.NightShifts
                });
            }
            RaisePropertyChanged(nameof(PersonStatistics));
        }

        private string SelectPersonForShift(Dictionary<string, PersonSchedule> personSchedules, DateTime shiftStartTime, int requiredRestHours, Random random, bool isDayShift)
        {
            // 首先尝试选择从未被排班或长时间未排班的人
            var availablePersons = personSchedules
                .Where(p => 
                    (shiftStartTime - p.Value.LastWorkTime).TotalHours >= requiredRestHours && // 确保有足够的休息时间
                    p.Value.ConsecutiveWorkDays < 5 && // 连续工作不超过5天
                    p.Value.LastWorkTime.Date != shiftStartTime.Date && // 确保同一天不会连续排班
                    (!isDayShift || p.Value.ConsecutiveNightShifts < 3) && // 连续夜班不超过3天
                    (isDayShift || p.Value.WeeklyNightShifts < 4)) // 每周夜班不超过4天
                .OrderBy(p => p.Value.TotalShifts) // 优先选择总班次少的人
                .ThenByDescending(p => p.Value.DaysSinceLastShift) // 其次选择长时间未排班的人
                .ThenBy(p => p.Value.ConsecutiveNightShifts) // 再次选择连续夜班少的人
                .ThenBy(p => p.Value.WeeklyNightShifts) // 最后选择周夜班少的人
                .Select(p => p.Key)
                .ToList();

            if (availablePersons.Count == 0)
            {
                return null;
            }

            // 如果有人的总班次数明显少于其他人，优先选择这些人
            var minShifts = availablePersons.Min(p => personSchedules[p].TotalShifts);
            var maxShifts = availablePersons.Max(p => personSchedules[p].TotalShifts);
            
            if (maxShifts - minShifts >= 2)
            {
                var priorityPersons = availablePersons.Where(p => personSchedules[p].TotalShifts == minShifts).ToList();
                return priorityPersons[random.Next(priorityPersons.Count)];
            }

            // 否则随机选择
            return availablePersons[random.Next(availablePersons.Count)];
        }

        private void UpdatePersonSchedule(PersonSchedule schedule, DateTime workTime, bool isDayShift)
        {
            if ((workTime - schedule.LastWorkTime).TotalHours < 24)
            {
                schedule.ConsecutiveWorkDays++;
            }
            else
            {
                schedule.ConsecutiveWorkDays = 1;
            }

            if (!isDayShift)
            {
                if ((workTime - schedule.LastWorkTime).TotalHours < 24)
                {
                    schedule.ConsecutiveNightShifts++;
                }
                else
                {
                    schedule.ConsecutiveNightShifts = 1;
                }
                schedule.WeeklyNightShifts++;
            }
            else
            {
                schedule.ConsecutiveNightShifts = 0;
            }

            schedule.LastWorkTime = workTime;
            schedule.TotalShifts++;
            schedule.DaysSinceLastShift = 0;
            if (isDayShift)
            {
                schedule.DayShifts++;
            }
            else
            {
                schedule.NightShifts++;
            }
        }

        private void UpdateSchedule(CalendarDay day)
        {
            if (day == null) return;

            var dayShifts = ScheduleResults.Where(r => r.Date.Date == day.Date.Date && r.ShiftType == "白班").ToList();
            var nightShifts = ScheduleResults.Where(r => r.Date.Date == day.Date.Date && r.ShiftType == "夜班").ToList();

            // 更新白班信息
            if (day.DayShift != null)
            {
                var personNames = day.DayShift.Replace("白班: ", "").Split(',').Select(n => n.Trim()).ToList();
                foreach (var personName in personNames)
                {
                    if (!dayShifts.Any(s => s.PersonName == personName))
                    {
                        ScheduleResults.Add(new ScheduleResult
                        {
                            ShiftNumber = dayShifts.Count + 1,
                            Date = day.Date,
                            ShiftType = "白班",
                            PersonName = personName,
                            WorkTime = "08:00-20:00"
                        });
                    }
                }
            }

            // 更新夜班信息
            if (day.NightShift != null)
            {
                var personNames = day.NightShift.Replace("夜班: ", "").Split(',').Select(n => n.Trim()).ToList();
                foreach (var personName in personNames)
                {
                    if (!nightShifts.Any(s => s.PersonName == personName))
                    {
                        ScheduleResults.Add(new ScheduleResult
                        {
                            ShiftNumber = nightShifts.Count + 1,
                            Date = day.Date,
                            ShiftType = "夜班",
                            PersonName = personName,
                            WorkTime = "20:00-08:00"
                        });
                    }
                }
            }

            UpdateCalendarView();
        }

        private void ExportToExcel()
        {
            var saveFileDialog = new SaveFileDialog
            {
                Filter = "Excel文件|*.xlsx",
                Title = "导出排班表"
            };

            if (saveFileDialog.ShowDialog() == true)
            {
                try
                {
                    ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
                    using (var package = new ExcelPackage())
                    {
                        var worksheet = package.Workbook.Worksheets.Add("排班表");

                        // 添加表头
                        worksheet.Cells[1, 1].Value = "日期";
                        worksheet.Cells[1, 2].Value = "班次";
                        worksheet.Cells[1, 3].Value = "人员";
                        worksheet.Cells[1, 4].Value = "工作时间";

                        // 添加数据
                        int row = 2;
                        foreach (var result in ScheduleResults.OrderBy(r => r.Date).ThenBy(r => r.ShiftType))
                        {
                            worksheet.Cells[row, 1].Value = result.Date.ToString("yyyy-MM-dd");
                            worksheet.Cells[row, 2].Value = result.ShiftType;
                            worksheet.Cells[row, 3].Value = result.PersonName;
                            worksheet.Cells[row, 4].Value = result.WorkTime;
                            row++;
                        }

                        // 自动调整列宽
                        worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();

                        // 保存文件
                        package.SaveAs(new FileInfo(saveFileDialog.FileName));
                    }

                    MessageBox.Show("导出成功！", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"导出失败：{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private void ExportToImage()
        {
            var saveFileDialog = new SaveFileDialog
            {
                Filter = "PNG图片|*.png",
                Title = "导出排班表"
            };

            if (saveFileDialog.ShowDialog() == true)
            {
                try
                {
                    // 获取日历视图的视觉树
                    var calendarView = Application.Current.Windows.OfType<Window>()
                        .FirstOrDefault(w => w.IsActive)?
                        .FindName("CalendarView") as ItemsControl;

                    if (calendarView == null)
                    {
                        MessageBox.Show("无法找到日历视图", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }

                    // 创建渲染目标
                    var renderTarget = new RenderTargetBitmap(
                        (int)calendarView.ActualWidth,
                        (int)calendarView.ActualHeight,
                        96, 96, PixelFormats.Pbgra32);

                    // 渲染视图
                    var visual = calendarView as Visual;
                    renderTarget.Render(visual);

                    // 保存为PNG
                    var encoder = new PngBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(renderTarget));

                    using (var stream = File.Create(saveFileDialog.FileName))
                    {
                        encoder.Save(stream);
                    }

                    MessageBox.Show("导出成功！", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"导出失败：{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private void ClearFilter()
        {
            SelectedFilterPerson = null;
            UpdateCalendarView();
        }
    }

    public class PersonItem : BindableBase
    {
        private string _name;
        public string Name
        {
            get => _name;
            set => SetProperty(ref _name, value);
        }

        private bool _isSelected;
        public bool IsSelected
        {
            get => _isSelected;
            set => SetProperty(ref _isSelected, value);
        }
    }

    public class ScheduleResult
    {
        public int ShiftNumber { get; set; }
        public DateTime Date { get; set; }
        public string ShiftType { get; set; }
        public string PersonName { get; set; }
        public string WorkTime { get; set; }
    }

    public class PersonStatistics
    {
        public string Name { get; set; }
        public int TotalShifts { get; set; }
        public int DayShifts { get; set; }
        public int NightShifts { get; set; }
    }

    public class CalendarDay : BindableBase
    {
        private DateTime _date;
        public DateTime Date
        {
            get => _date;
            set => SetProperty(ref _date, value);
        }

        private string _dayShift;
        public string DayShift
        {
            get => _dayShift;
            set => SetProperty(ref _dayShift, value);
        }

        private string _nightShift;
        public string NightShift
        {
            get => _nightShift;
            set => SetProperty(ref _nightShift, value);
        }

        private bool _hasDayShift;
        public bool HasDayShift
        {
            get => _hasDayShift;
            set => SetProperty(ref _hasDayShift, value);
        }

        private bool _hasNightShift;
        public bool HasNightShift
        {
            get => _hasNightShift;
            set => SetProperty(ref _hasNightShift, value);
        }

        private bool _isRestDay;
        public bool IsRestDay
        {
            get => _isRestDay;
            set => SetProperty(ref _isRestDay, value);
        }
    }
} 